function getSequence(arr) {
  const p = arr.slice(); // 复制一份数组，用于存储索引
  const result = [0]; // 初始化结果数组，第一个元素为 0
  let i, j, u, v, c; // 定义变量

  const  len = arr.length; // 数组长度
  for (i = 0; i < len; i++) {
    const arrI = arr[i]; // 当前元素
    if (arrI !== 0) { // 如果当前元素不是 0
      j = result[result.length - 1]; // 获取结果数组的最后一个元素
      if (arr[j] < arrI) { // 如果结果数组的最后一个元素对应的原数组元素小于当前元素
        p[i] = j; // 存储当前元素的前一个元素的索引
        result.push(i); // 将当前元素的索引添加到结果数组中
        continue; // 继续下一轮循环
      } // 如果结果数组的最后一个元素对应的原数组元素大于等于当前元素
      u = 0; // 初始化左边界
      v = result.length - 1; // 初始化右边界
      while (u < v) { // 二分查找
        c = ((u + v) / 2) | 0; // 计算中间索引  | 0 是取整
        if (arr[result[c]] < arrI) { // 如果中间元素对应的原数组元素小于当前元素
          u = c + 1; // 更新左边界
        } else { // 如果中间元素对应的原数组元素大于等于当前元素
          v = c; // 更新右边界
        } // 二分查找结束后，u 指向大于等于当前元素的第一个元素的索引
      } // 如果当前元素小于等于结果数组的最后一个元素对应的原数组元素
      
      if (arrI < arr[result[u]]) { // 如果当前元素小于等于结果数组的最后一个元素对应的原数组元素
        if (u > 0) { // 如果 u 大于 0，即找到了一个小于当前元素的元素
          p[i] = result[u - 1]; // 存储当前元素的前一个元素的索引
        } // 更新结果数组中 u 位置的元素为当前元素的索引
        result[u] = i; // 更新结果数组中 u 位置的元素为当前元素的索引
      } // 如果当前元素大于结果数组的最后一个元素对应的原数组元素
    } // 如果当前元素是 0，不做任何操作，继续下一轮循环   0 是哨兵，哨兵是一个特殊的元素，它的作用是用来表示数组的边界，或者是用来表示数组的结束。   

    u=result.length; // 获取结果数组的长度
    v=result[u-1]; // 获取结果数组的最后一个元素的索引
    while(u-- && v!==0){ // 从结果数组的最后一个元素开始向前遍历，直到找到第一个元素的索引为 0 的元素
      result[u]=v; // 将当前元素的索引赋值给结果数组中 u 位置的元素
      v=p[v]; // 将当前元素的前一个元素的索引赋值给 v，继续向前遍历
    }

    return result; // 返回结果数组

  }
}